#ifndef _GDI_UTILS_
#define _GDI_UTILS_

#include "Vertex.h"
#include "Polygon.h"

// helper template function for unused parameters
template <class T>
void Unused(T rT)
{
    static_cast<void>(rT);
};

// the base class
class CGDI
{
protected:
    CDC* m_pDC;

    CGDI(CDC* pDC) : 
      m_pDC(pDC)
    {
    }

    virtual ~CGDI()
    {
        m_pDC = NULL;
    }
};

// Class to select a stock object
// CGDISelectStockObject tmp(pDC, BLACK_BRUSH);
class CGDISelectStockObject : public CGDI
{
    CGdiObject* m_pLastObject;

public:
    CGDISelectStockObject(CDC* pDC, int nIndex) : CGDI(pDC),
      m_pLastObject(NULL)
    {
        m_pLastObject = m_pDC->SelectStockObject(nIndex);
    }

    virtual ~CGDISelectStockObject()
    {
        if (m_pLastObject)
        {
            Unused(m_pDC->SelectObject(m_pLastObject));

            m_pLastObject = NULL;
        }
    }
};


// CGDISetTextColor tmp( pDC, COLORREF(0,0,0) );
class CGDISetTextColor : public CGDI
{
    COLORREF m_LastColor;

public:
    CGDISetTextColor(CDC* pDC, COLORREF theColor) : CGDI(pDC),
      m_LastColor(DefaultColor)
    {
        m_LastColor = m_pDC->SetTextColor(theColor);
    }

    virtual ~CGDISetTextColor()
    {
        Unused(m_pDC->SetTextColor(m_LastColor));
    }

};

// CGDISetBkColor tmp( pDC, COLORREF(0,250,0) );
class CGDISetBkColor : public CGDI
{
    COLORREF m_LastColor;

public:
    CGDISetBkColor(CDC* pDC, COLORREF theColor) : CGDI(pDC),
      m_LastColor(DefaultColor)
    {
        m_LastColor = m_pDC->SetBkColor(theColor);
    }

    virtual ~CGDISetBkColor()
    {
        Unused(m_pDC->SetBkColor(m_LastColor));
    }

};

// CGDISetBkMode tmp( pDC, TRANSPARENT );
class CGDISetBkMode : public CGDI
{
    int m_LastMode;

public:
    CGDISetBkMode(CDC* pDC, int theMode) : CGDI(pDC),
	  m_LastMode(0)
    {
        m_LastMode = m_pDC->SetBkMode(theMode);
    }

    virtual ~CGDISetBkMode()
    {
        Unused(m_pDC->SetBkMode(m_LastMode));
    }

};


// CGDISelectObject<CPen>		tmp(pDC, pPen);
// CGDISelectObject<CBrush>		tmp(pDC, pBrush);
// CGDISelectObject<CFont>		tmp(pDC, pFont);
// CGDISelectObject<CBitmap>	tmp(pDC, pBitmap);
// CGDISelectObject<CRgn>		tmp(pDC, pRgn);
// CGDISelectObject<CGdiObject>	tmp(pDC, pGdiObject);
template <class T>
class CGDISelectObject : public CGDI
{
	T*	m_pLast;

public:
    CGDISelectObject(CDC* pDC, T* pObject) : CGDI(pDC), 
	  m_pLast(NULL)
    {
		Set( pDC, pObject );
        //if (pObject)
        //{
        //    m_pLast = pDC->SelectObject(pObject);
        //}
    }

    virtual ~CGDISelectObject()
    {
        if (m_pLast)
        {
            Unused(m_pDC->SelectObject(m_pLast));

            m_pLast = NULL;
        }
    }

	void	Set(CDC* pDC, T* pObject)
	{
		m_pDC = pDC;
        if (pObject)
        {
            m_pLast = pDC->SelectObject(pObject);
        }
	}
};


// CGDISetTextAlign tmp(pDC, TA_CENTER);
class CGDISetTextAlign : public CGDI
{
	UINT	m_Last;

public:
    CGDISetTextAlign(CDC* pDC, UINT nTextAlign) : CGDI(pDC),
	  m_Last(0)
    {
        m_Last = pDC->SetTextAlign(nTextAlign);
    }

    virtual ~CGDISetTextAlign()
    {
        Unused(m_pDC->SetTextAlign(m_Last));
    }
};



// CGDISetROP tmp(pDC, R2_NOT);
class CGDISetROP : public CGDI
{
	int		m_Last;

public:
    CGDISetROP(CDC* pDC, int nROP) : CGDI(pDC),
	  m_Last(0)
    {
		Set( pDC, nROP );
        //m_Last = pDC->SetROP2(nROP);
    }

    virtual ~CGDISetROP()
    {
        Unused(m_pDC->SetROP2(m_Last));
    }

	void Set(CDC* pDC, int nROP)
	{
		m_pDC = pDC ;
        m_Last = pDC->SetROP2(nROP);
	}
};


//CGDISetMapMode	tmp( pDC, MM_ANISOTROPIC );
class CGDISetMapMode : public CGDI
{
	int		m_Last;

public:
    CGDISetMapMode(CDC* pDC, int nMapMode) : CGDI(pDC),
	  m_Last(0)
    {
        m_Last = pDC->SetMapMode(nMapMode);
    }

    virtual ~CGDISetMapMode()
    {
        Unused(m_pDC->SetMapMode(m_Last));
    }
};



///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//										useful GDI functions
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
class CGDIUtils
{
public:
	CGDIUtils();
	virtual ~CGDIUtils();

	// vector graphics drawing
	static void			DrawLine( CDC *pDC, CPoint From, CPoint To );
	static void			DrawLine( CDC *pDC, CPoint From, CPoint To, COLORREF color );
	static void			DrawAxis( CDC *pDC );
	static void			DrawRubberRect( CDC *pDC, CPoint From, CPoint To );
	static void			DrawText( CDC* pDC, CPoint Location, CString strText, CString strFontName, 
		int nFontWidth, int nFontHeight, COLORREF crFontColour, long FontWeight=FW_BOLD);
	static void			DrawText(	CDC *pDC, CRect rect, CString strText, CString strFontName, COLORREF crFontColour, long FontWeight=FW_BOLD);
	static void			PaintHatch( CDC* pDC, CRect area, COLORREF crFG=RGB(0,70,30), COLORREF crBG=NULL);
	static void			DrawEllipse( CDC *pDC, CPoint From, CPoint To );

	// bitmap image processing
	static void			LoadBitmap( CBitmap *pBitmap, const char *file );
	static void			DrawBitmap( CDC *pDC, CBitmap *pBitmap, int X, int Y );
	static void			DrawBitmap(CDC *pDC, CBitmap *pBitmap, int X, int Y, double xScale, double yScale );
	static void			DrawBitmap(CDC *pDC, CBitmap *pBitmap, int X, int Y, int width, int height );
	static void			DrawGrids(CDC *pDC, CRect rect, int offset);
	static void			DrawFilledBox(CDC *pDC, CPoint center, int nSize, COLORREF color=DefaultColor );
	static void			DrawFilledBox(CDC *pDC, CRect &rect, COLORREF color=DefaultColor );
	static void			DrawFilledBox(CDC *pDC, CPoint pt1, CPoint pt2, COLORREF color=DefaultColor );
	static void			DrawFilledCircle(CDC *pDC, CPoint center, int nSize, COLORREF color=DefaultColor );


	// here is some useful non-GDI utils, including some math functions
	static BOOL			PointOnLine(int x, int y, int x1, int y1, int x2, int y2, double &ratio);
	static BOOL			PointOnLine(double x, double y, double x1, double y1, double x2, double y2, double &ratio);
	static BOOL			PointOnLine( CPoint p, CPoint p1, CPoint p2, double &ratio );
	static BOOL			PointInPoint( double x, double y, double x1, double y1 );
	static BOOL			RectInRect( CRect &rect1, CRect &rect2 );
	static BOOL			InInterval( int x, int x0, int x1 );
	static CRect		UnionRect( CRect &rect1, CRect &rect2 );
	static CPoint		GetNearestCorner( CPoint pt, CRect rect );

	static double		Distance(const CVertex &p0, const CVertex &p1);
	static double		Angle(const CVertex &p0, const CVertex &p1);
	static double		CalcAngle(const CVertex &p0, const CVertex &p1, const CVertex &p2, const CVertex &p3);
};


#endif  // _GDI_UTILS_